package com.dmn.gcode.springchains;

import com.dmn.gcode.springchains.core.IChainMaster;
import com.dmn.gcode.springchains.core.IOperator;

import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Basic Chain Master implementation.
 * <p/>
 *
 *
 * date 18.01.11
 *
 * @author dvponomarev
 * @version 1.0
 */
public class ChainMaster implements IChainMaster {
    private LinkedList<IOperator> operatorStack = new LinkedList<IOperator>();
    private AtomicBoolean stopRequested = new AtomicBoolean(false);

    /**
     * Execute operator.
     *
     * @param operator operator to execute.
     * @throws ChainInterruptedException chain execution was interrupted
     *                                   by user request, see {@link #requestChainStop}.
     * @throws Throwable                 error in chain execution or one of operators failed.
     */
    public void execute(IOperator operator) throws Throwable {
        if (stopRequested.get()) {
            throw new ChainInterruptedException();
        }
        try {
            operatorStack.add(operator);
            operator.execute(this);
            operatorStack.removeLast();
        } catch (Throwable e) {
            throw new Exception("Chain failed to execute: " + getOperatorsStackTraceString(), e);
        }
    }

    /**
     * Example:<br/><tt>1:SequenceOperator{fullConditionalRun}
     * 2:IfOperator{com.dmn.gcode.springchains.baseoperators.IfOperator#1955e0bc}
     * 3:ImportXmlToXlpOperator{importXmlToXlpOperator}</tt>
     */
    protected String getOperatorsStackTraceString() {
        StringBuilder sb = new StringBuilder();
        int index = 0;
        for (IOperator operator : operatorStack) {
            index++;
            sb.append(index).append(":").append(getStackTraceOperatorName(operator)).append(" ");
        }
        if (sb.length() > 0) {
            sb.setLength(sb.length() - 1);
        }
        return sb.toString();
    }

    /**
     * <ul>Examples:
     * <li><tt>1:SequenceOperator{fullConditionalRun}</tt>
     * <li><tt>2:IfOperator{com.dmn.gcode.springchains.baseoperators.IfOperator#1955e0bc}</tt>
     * </ul>
     */
    protected String getStackTraceOperatorName(IOperator operator) {
        return new StringBuilder().
            append(operator.getClass().getSimpleName()).
            append("{").append(operator.getBeanName()).append("}").toString();
    }

    /**
     * Asynchronous request to stop chain execution.<br/>
     * Currently executing command will be completed but next ones will be cancelled.
     */
    public void requestChainStop() {
        stopRequested.set(true);
    }
}
